using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Xna.Framework;

namespace Xfinity.Maths.Curves
{
    /// <summary>
    /// A 3D Bezier curve.
    /// </summary>
    public struct BezierCurve 
    {
        /// <summary>
        /// A control point.
        /// </summary>
        public Vector3 ControlPointA, ControlPointB, ControlPointC;

        /// <summary>
        /// Constructs a new 3D Bezier curve.
        /// </summary>
        /// <param name="a">Control point A.</param>
        /// <param name="b">Control point B.</param>
        /// <param name="c">Control point C.</param>
        public BezierCurve(Vector3 a, Vector3 b, Vector3 c)
        {
            ControlPointA = a;
            ControlPointB = b;
            ControlPointC = c;
        }

        /// <summary>
        /// Evaluate the curve.
        /// </summary>
        /// <param name="t">The interpolant.</param>
        /// <returns>The point represented by the Bezier parametric equation.</returns>
        public Vector3 Evaluate(float t)
        {
            float oneMinusT = 1 - t;
            float omtSquared = oneMinusT * oneMinusT;
            return omtSquared * ControlPointA + 2 * t * oneMinusT * ControlPointB + t * t * ControlPointC;
        }

        /// <summary>
        /// Evaluates a higher order curve. This can be called recursively. However, for anything more than a cubic
        /// Bezier curve, it'd be better to call MathFunctions.BezierCurve.
        /// </summary>
        /// <param name="left">The curve on the left.</param>
        /// <param name="t">The interpolant.</param>
        /// <param name="right">The curve on the right.</param>
        /// <returns>The point represented by the Bezier parametric equation.</returns>
        public Vector3 EvaluateHigherOrder(BezierCurve left,  float t,BezierCurve right)
        {
            Vector3 leftPoint, @this, rightPoint;

            leftPoint = left.Evaluate(t);
            rightPoint = right.Evaluate(t);
            @this = this.Evaluate(t);

            BezierCurve curve = new BezierCurve(leftPoint, @this, rightPoint);
            return curve.Evaluate(t);            
        }
    }
}